package com.kuizii.base.aspect;


import com.kuizii.base.annotaion.AuditLog;
import com.kuizii.base.config.AuditLogConfigProperties;
import com.kuizii.base.domain.BaseResponse;
import com.kuizii.base.domain.OptStatus;
import com.kuizii.base.util.IpUtil;
import com.kuizii.base.util.log.ILogWriter;
import com.kuizii.base.util.log.LogEntity;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author rxd
 */
@Aspect
@Component
public class AuditLogAspect {

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    ILogWriter logWriter;

    @Autowired
    AuditLogConfigProperties auditLogConfigProperties;


    @Autowired(required = false)
    IAuditLogHandler auditLogHandler;

    static ExecutorService executorService = new ThreadPoolExecutor(0, 5,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());


    @Pointcut("@annotation(com.kuizii.base.annotaion.AuditLog)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        AuditLog syslog = method.getAnnotation(AuditLog.class);

        LogEntity logEntity = new LogEntity();
        //获取方法执行前时间
        long beginTime = System.currentTimeMillis();
        logEntity.setBeginTime(LocalDateTime.now().format(formatter));
        Object result = joinPoint.proceed();
        if (auditLogHandler != null) {
            auditLogHandler.setProcessResult(result);
            auditLogHandler.setArgs(joinPoint.getArgs());
            logEntity.setApplicationId(auditLogHandler.getApplicationId());
            logEntity.setApplicationName(auditLogHandler.getApplicationName());
            logEntity.setToken(auditLogHandler.getToken());
            logEntity.setUserName(auditLogHandler.getUserName());
            logEntity.setUserCode(auditLogHandler.getUserCode());
        }
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            //获取请求的ip
            String ip = IpUtil.getIpAddress(request);
            logEntity.setIp(ip);
            //获取请求URL
            logEntity.setRequestUri(request.getRequestURI());
        }
        //获取执行的类名
        logEntity.setMethodClass(joinPoint.getTarget().getClass().getName());
        //获取执行的方法名
        logEntity.setMethodName(joinPoint.getSignature().getName());
        logEntity.setType(syslog.logType());
        logEntity.setActionType(syslog.actionType());
        logEntity.setDescription(syslog.description());
        if (StringUtils.isNotEmpty(syslog.spel())) {
            String elString = getElString(joinPoint.getArgs(), syslog.spel());
            logEntity.setSpelMessage(elString);
        }
        if (result instanceof BaseResponse) {
            BaseResponse res = (BaseResponse) result;
            //设置操作信息
            logEntity.setOptStatus(res.getOptStatus());
            logEntity.setMessage(res.getMessage());
            logEntity.setDetailMsg(res.getDetailMsg());
        } else {
            logEntity.setOptStatus(OptStatus.OK);
        }
        logEntity.setTermType("1");
        logEntity.setEndTime(LocalDateTime.now().format(formatter));
        logEntity.setTotalTime(String.valueOf(System.currentTimeMillis() - beginTime));
        executorService.execute(() -> {
            logWriter.writer(logEntity);
        });
        return result;

    }

    private String getElString(Object[] args, String spel) {
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("args", args);

        String value = spel;
        ExpressionParser parser = new SpelExpressionParser();
        try {
            value = Objects.requireNonNull(parser.parseExpression(spel).getValue(context)).toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }


}
